/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.util;

/**
 *
 * @author nbzhang
 */
public class Utility {

	private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

	private Utility() {
	}

	public static char[] binToHex(byte[] bytes) {
		return binToHex(bytes, 0, bytes.length);
	}

	public static char[] binToHex(byte[] bytes, int offset, int len) {
		final char[] sb = new char[len * 2];
		final int end = offset + len;
		int index = 0;
		for (int i = offset; i < end; i++) {
			byte b = bytes[i];
			sb[index++] = (hex[((b >> 4) & 0xF)]);
			sb[index++] = hex[((b) & 0xF)];
		}
		return sb;
	}

	public static byte[] hexToBin(CharSequence src) {
		return hexToBin(src, 0, src.length());
	}

	public static byte[] hexToBin(CharSequence src, int offset, int len) {
		final int size = (len + 1) / 2;
		final byte[] bytes = new byte[size];
		final int end = offset + len;
		String digits = "0123456789abcdef";
		for (int i = 0; i < size; i++) {
			int ch1 = src.charAt(offset + i * 2);
			if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a';
			int ch2 = src.charAt(offset + i * 2 + 1);
			if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a';
			int pos1 = digits.indexOf(ch1);
			if (pos1 < 0) throw new NumberFormatException();
			int pos2 = digits.indexOf(ch2);
			if (pos2 < 0) throw new NumberFormatException();
			bytes[i] = (byte) (pos1 * 0x10 + pos2);
		}
		return bytes;
	}

	public static byte[] hexToBin(char[] src) {
		return hexToBin(src, 0, src.length);
	}

	public static byte[] hexToBin(char[] src, int offset, int len) {
		final int size = (len + 1) / 2;
		final byte[] bytes = new byte[size];
		final int end = offset + len;
		String digits = "0123456789abcdef";
		for (int i = 0; i < size; i++) {
			int ch1 = src[offset + i * 2];
			if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a';
			int ch2 = src[offset + i * 2 + 1];
			if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a';
			int pos1 = digits.indexOf(ch1);
			if (pos1 < 0) throw new NumberFormatException();
			int pos2 = digits.indexOf(ch2);
			if (pos2 < 0) throw new NumberFormatException();
			bytes[i] = (byte) (pos1 * 0x10 + pos2);
		}
		return bytes;
	}

	//-----------------------------------------------------------------------------
	public static char[] decodeUTF8(final byte[] array) {
		return decodeUTF8(array, 0, array.length);
	}

	public static char[] decodeUTF8(final byte[] array, final int start, final int len) {
		byte b;
		int size = len;
		final byte[] bytes = array;
		final int limit = start + len;
		for (int i = start; i < limit; i++) {
			b = bytes[i];
			if ((b >> 5) == -2) {
				size--;
			} else if ((b >> 4) == -2) {
				size -= 2;
			}
		}
		final char[] text = new char[size];
		size = 0;
		for (int i = start; i < limit;) {
			b = bytes[i++];
			if (b >= 0) {
				text[size++] = (char) b;
			} else if ((b >> 5) == -2) {
				text[size++] = (char) (((b << 6) ^ bytes[i++]) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80)));
			} else if ((b >> 4) == -2) {
				text[size++] = (char) ((b << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
			}
		}
		return text;
	}

	public static byte[] encodeUTF8(final char[] array) {
		return encodeUTF8(array, 0, array.length);
	}

	public static byte[] encodeUTF8(final char[] text, final int start, final int len) {
		char c;
		int size = 0;
		final char[] chars = text;
		final int limit = start + len;
		for (int i = start; i < limit; i++) {
			c = chars[i];
			if (c < 0x80) {
				size++;
			} else if (c < 0x800) {
				size += 2;
			} else {
				size += 3;
			}
		}
		final byte[] bytes = new byte[size];
		size = 0;
		for (int i = start; i < limit; i++) {
			c = chars[i];
			if (c < 0x80)
				bytes[size++] = (byte) c;
			else if (c < 0x800) {
				bytes[size++] = (byte) (0xc0 | (c >> 6));
				bytes[size++] = (byte) (0x80 | (c & 0x3f));
			} else {
				bytes[size++] = (byte) (0xe0 | ((c >> 12)));
				bytes[size++] = (byte) (0x80 | ((c >> 6) & 0x3f));
				bytes[size++] = (byte) (0x80 | (c & 0x3f));
			}
		}
		return bytes;
	}
}
